﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Web;
using Interscape.TwilioClient.Components;
using Interscape.TwilioClient.ServiceHelpers;
using Microsoft.Http;

namespace Interscape.TwilioClient
{

    #region Service Interface

    [ServiceContract]
    public interface IIncomingPhoneNumberManager
    {
        [OperationContract]
        [TwilioWcfSerializer]
        [WebGet(
            BodyStyle = WebMessageBodyStyle.Bare,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/Accounts/{accountSid}/IncomingPhoneNumbers"
            )]
        IncomingPhoneNumberList GetAll(string accountSid);

        [OperationContract]
        [TwilioWcfSerializer]
        [WebGet(
            BodyStyle = WebMessageBodyStyle.Bare,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/Accounts/{accountSid}/IncomingPhoneNumbers/Local"
            )]
        IncomingPhoneNumberList GetLocal(string accountSid);

        [OperationContract]
        [TwilioWcfSerializer]
        [WebGet(
            BodyStyle = WebMessageBodyStyle.Bare,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/Accounts/{accountSid}/IncomingPhoneNumbers/TollFree"
            )]
        IncomingPhoneNumberList GetTollFree(string accountSid);

        [OperationContract]
        [TwilioWcfSerializer]
        [WebGet(
            BodyStyle = WebMessageBodyStyle.Bare,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/Accounts/{accountSid}/IncomingPhoneNumbers/{phoneNumberSid}"
            )]
        IncomingPhoneNumber Get(string accountSid, string phoneNumberSid);

        [OperationContract]
        [WebInvoke(
            Method = "DELETE",
            BodyStyle = WebMessageBodyStyle.WrappedResponse,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/Accounts/{accountSid}/IncomingPhoneNumbers/{phoneNumberSid}"
            )]
        void Delete(string accountSid, string phoneNumberSid);

    }

    #endregion

    /// <summary>
    /// 
    /// </summary>
    public class IncomingPhoneNumberManager : ManagerBase<IIncomingPhoneNumberManager>, IIncomingPhoneNumberManager
    {

        #region Constructors

        /// <summary>
        /// Creates a new instance of the IncomingPhoneNumberManager.
        /// </summary>
        /// <param name="accountSid">The 34 character string that uniquely identifies the Account which will be used to make the TwilioAPI requests.</param>
        /// <param name="authToken">The "password" for your Twilio API calls.</param>
        public IncomingPhoneNumberManager(string accountSid, string authToken) : base(accountSid, authToken)
        {
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IncomingPhoneNumberList GetAll()
        {
            return this.GetAll(this.AccountSid);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="accountSid">A 34 character string that uniquely identifies the Account associated with this resource.</param>
        /// <returns></returns>
        public IncomingPhoneNumberList GetAll(string accountSid)
        {
            return this.Channel.GetAll(accountSid);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IncomingPhoneNumberList GetLocal()
        {
            return this.GetLocal(this.AccountSid);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="accountSid">A 34 character string that uniquely identifies the Account associated with this resource.</param>
        /// <returns></returns>
        public IncomingPhoneNumberList GetLocal(string accountSid)
        {
            return this.Channel.GetLocal(accountSid);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IncomingPhoneNumberList GetTollFree()
        {
            return this.Channel.GetTollFree(this.AccountSid);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IncomingPhoneNumberList GetTollFree(string accountSid)
        {
            return this.Channel.GetTollFree(accountSid);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="phoneNumberSid"></param>
        /// <returns></returns>
        public IncomingPhoneNumber Get(string phoneNumberSid)
        {
            return this.Get(this.AccountSid, phoneNumberSid);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="accountSid">A 34 character string that uniquely identifies the Account associated with this resource.</param>
        /// <param name="phoneNumberSid"></param>
        /// <returns></returns>
        public IncomingPhoneNumber Get(string accountSid, string phoneNumberSid)
        {
            return this.Channel.Get(accountSid, phoneNumberSid);
        }

        /// <summary>
        /// Release this phone number from your account. 
        /// </summary>
        /// <param name="phoneSid">A 34 character string that uniquely identifies the resource to be deleted.</param>
        /// <remarks>
        /// Twilio will no longer answer calls to this number, and you will stop being billed the monthly phone number fees. 
        /// The phone number will eventually be recycled and potentially given to another customer, so use with care. 
        /// If you make a mistake, contact us... we may be able to give you the number back. 
        /// </remarks>
        public void Delete(string phoneSid)
        {
            this.Delete(this.AccountSid, phoneSid);
        }

        /// <summary>
        /// Release this phone number from your account. 
        /// </summary>
        /// <param name="accountSid"></param>
        /// <param name="phoneNumberSid">A 34 character string that uniquely identifies the resource to be deleted.</param>
        /// <remarks>
        /// Twilio will no longer answer calls to this number, and you will stop being billed the monthly phone number fees. 
        /// The phone number will eventually be recycled and potentially given to another customer, so use with care. 
        /// If you make a mistake, contact us... we may be able to give you the number back. 
        /// </remarks>
        public void Delete(string accountSid, string phoneNumberSid)
        {
            this.Channel.Delete(accountSid, phoneNumberSid);
        }

        /// <summary>
        /// Allows you to add a new local phone number to your account.
        /// </summary>
        /// <param name="ipn">The <see cref="IncomingPhoneNumber">IncomingPhoneNumber</see> to submit to Twilio.</param>
        /// <returns></returns>
        /// <remarks>
        ///If a phone number is found for your request, it will be added to your account and your account balance will be decremented for the first month's cost of the phone number. 
        ///If Twilio couldn't find a phone number that matched your request, you will receive an HTTP 400, with Twilio error code 21452. 
        /// </remarks>
        public IncomingPhoneNumber AddLocal(IncomingPhoneNumber ipn)
        {
            System.Net.ServicePointManager.Expect100Continue = false;
            HttpUrlEncodedForm form = new HttpUrlEncodedForm();

            PopulateHttpForm(ref form, ref ipn);
            return ProcessResponse(this.HttpClientHelper.Post(this.Urls.IncomingPhoneNumberLocalUrl(true), form.CreateHttpContent()));
        }

        /// <summary>
        /// Allows you to add a new toll-free phone number to your account.
        /// </summary>
        /// <param name="ipn">The <see cref="IncomingPhoneNumber">IncomingPhoneNumber</see> to submit to Twilio.</param>
        /// <returns></returns>
        /// <remarks>
        ///If a phone number is found for your request, it will be added to your account and your account balance will be decremented for the first month's cost of the phone number. 
        ///If Twilio couldn't find a phone number that matched your request, you will receive an HTTP 400, with Twilio error code 21452. 
        /// </remarks>
        public IncomingPhoneNumber AddTollFree(IncomingPhoneNumber ipn)
        {
            System.Net.ServicePointManager.Expect100Continue = false;
            HttpUrlEncodedForm form = new HttpUrlEncodedForm();

            PopulateHttpForm(ref form, ref ipn);
            return ProcessResponse(this.HttpClientHelper.Post(this.Urls.IncomingPhoneNumberTollFreeUrl(true), form.CreateHttpContent()));
      
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ipn"></param>
        /// <returns></returns>
        public IncomingPhoneNumber Update(IncomingPhoneNumber ipn)
        {
            System.Net.ServicePointManager.Expect100Continue = false;
            HttpUrlEncodedForm form = new HttpUrlEncodedForm();

            PopulateHttpForm(ref form, ref ipn);
            return ProcessResponse(this.HttpClientHelper.Put(this.Urls.IncomingPhoneNumberTollFreeUrl(true), form.CreateHttpContent()));
        }

        #region Private Helper Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="form"></param>
        /// <param name="ipn"></param>
        private void PopulateHttpForm(ref HttpUrlEncodedForm form, ref IncomingPhoneNumber ipn)
        {
            if (string.IsNullOrEmpty(ipn.Url)) throw new ArgumentNullException("The URL for an IncomingPhoneNumber is required.");
            form.Add("Url", ipn.Url);
            if (!string.IsNullOrEmpty(ipn.Method)) form.Add("Method", ipn.Method);
            if (!string.IsNullOrEmpty(ipn.FriendlyName)) form.Add("FriendlyName", ipn.FriendlyName);
            foreach (KeyValuePair<string, string> arg in ipn.PostArguments)
            {
                form.Add(arg.Key, arg.Value);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        private IncomingPhoneNumber ProcessResponse(HttpResponseMessage response)
        {
            return (IncomingPhoneNumber)ServiceUtility.ProcessHttpResponseMessage(response, typeof(IncomingPhoneNumber));
        }

        #endregion

    }
}
